package org.example.springboot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.example.springboot.common.utils.Result;
import org.example.springboot.dao.UserDao;
import org.example.springboot.entity.User;
import org.example.springboot.service.UserService;
import org.example.springboot.utils.BcryptTool;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService {

    private static final int MAX_ATTEMPTS = 3;

    private static final long LOCK_TIME = 10;

    private static final long EXPIRATION_TIME_IN_MINUTES = 30;

    @Resource
    StringRedisTemplate stringRedisTemplate;

    // 用户登录
    public Result<Object> login(String username, String password) {
        // 从数据库中获取用户
        User user = this.findByUsername(username);
        if (user == null) {
            return Result.error("用户不存在");
        }
        // 检查账户是否被锁定
        if (isAccountLocked(username)) {
            return Result.error("账户被锁定");
        }
        // 验证密码
        if (checkPassword(password, user.getPassword())) {
            // 重置失败尝试次数
            resetFailedAttempts(username);
            //保存用户登录状态并返回token
            return Result.ok(setUserLoggedIn(user));
        } else {
            // 增加失败尝试次数'
            incrementFailedAttempts(username);
            return Result.error("请输入正确密码！");
        }
    }

    public Result<Object> loginOut(String username) {
        stringRedisTemplate.delete(username);
        return Result.ok();
    }

    //查询用户是否存在
    private User findByUsername(String username) {
        return this.getOne(new QueryWrapper<User>().eq("username", username));
    }

    // 校验密码
    private boolean checkPassword(String password, String userPassword) {
        return BcryptTool.checkPassword(password, userPassword);
    }

    //保存用户登录状态
    private HashMap<String, Object> setUserLoggedIn(User user) {
        String token = UUID.randomUUID().toString();
        stringRedisTemplate.opsForValue().set(token, user.getUsername(), EXPIRATION_TIME_IN_MINUTES, TimeUnit.MINUTES);
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("token", token);
        user.setUserId(String.valueOf(user.getId()));
        resultMap.put("userInfo", user);
        return resultMap;
    }

    // 检查账户是否被锁定
    private boolean isAccountLocked(String username) {
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
        String attempts = ops.get("login:attempts:" + username);
        return attempts != null && Integer.parseInt(attempts) >= MAX_ATTEMPTS;
    }

    // 重置失败尝试次数
    private void resetFailedAttempts(String username) {
        stringRedisTemplate.delete("login:attempts:" + username);
    }

    // 增加失败尝试次数
    private void incrementFailedAttempts(String username) {
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
        ops.increment("login:attempts:" + username);
        stringRedisTemplate.expire("login:attempts:" + username, LOCK_TIME, TimeUnit.SECONDS);
    }

}
